home

Load Libraries


### https://cran.r-project.org/web/packages/udpipe/vignettes/udpipe-usecase-postagging-lemmatisation.html
library(udpipe)
ud_model <- udpipe_download_model(language = "english")
library(tidyverse)
library(tidyr)
library(dplyr)
library(ggplot2)
library(ggrepel)
library(knitr)
library(tm)
library(quanteda)
library(lattice)
library(latticeExtra)
library(plotly)
library(pdp)
library(patchwork)
library(lubridate)

Load the FW functions


### CODE DIRECTLY FROM: https://burtmonroe.github.io/TextAsDataCourse/Tutorials/TADA-FightinWords.nb.html#
fwgroups <- function(dtm, groups, pair = NULL, weights = rep(1,nrow(dtm)), k.prior = .1) {
  
  weights[is.na(weights)] <- 0
  
  weights <- weights/mean(weights)
  
  zero.doc <- rowSums(dtm)==0 | weights==0
  zero.term <- colSums(dtm[!zero.doc,])==0
  
  dtm.nz <- apply(dtm[!zero.doc,!zero.term],2,"*", weights[!zero.doc])
  
  g.prior <- tcrossprod(rowSums(dtm.nz),colSums(dtm.nz))/sum(dtm.nz)
  
  # 
  
  g.posterior <- as.matrix(dtm.nz + k.prior*g.prior)
  
  groups <- groups[!zero.doc]
  groups <- droplevels(groups)
  
  g.adtm <- as.matrix(aggregate(x=g.posterior,by=list(groups=groups),FUN=sum)[,-1])
  rownames(g.adtm) <- levels(groups)
  
  g.ladtm <- log(g.adtm)
  
  g.delta <- t(scale( t(scale(g.ladtm, center=T, scale=F)), center=T, scale=F))
  
  g.adtm_w <- -sweep(g.adtm,1,rowSums(g.adtm)) # terms not w spoken by k
  g.adtm_k <- -sweep(g.adtm,2,colSums(g.adtm)) # w spoken by groups other than k
  g.adtm_kw <- sum(g.adtm) - g.adtm_w - g.adtm_k - g.adtm # total terms not w or k 
  
  g.se <- sqrt(1/g.adtm + 1/g.adtm_w + 1/g.adtm_k + 1/g.adtm_kw)
  
  g.zeta <- g.delta/g.se
  
  g.counts <- as.matrix(aggregate(x=dtm.nz, by = list(groups=groups), FUN=sum)[,-1])
  
  if (!is.null(pair)) {
    pr.delta <- t(scale( t(scale(g.ladtm[pair,], center = T, scale =F)), center=T, scale=F))
    pr.adtm_w <- -sweep(g.adtm[pair,],1,rowSums(g.adtm[pair,]))
    pr.adtm_k <- -sweep(g.adtm[pair,],2,colSums(g.adtm[pair,])) # w spoken by groups other than k
    pr.adtm_kw <- sum(g.adtm[pair,]) - pr.adtm_w - pr.adtm_k - g.adtm[pair,] # total terms not w or k
    pr.se <- sqrt(1/g.adtm[pair,] + 1/pr.adtm_w + 1/pr.adtm_k + 1/pr.adtm_kw)
    pr.zeta <- pr.delta/pr.se
    
    return(list(zeta=pr.zeta[1,], delta=pr.delta[1,],se=pr.se[1,], counts = colSums(dtm.nz), acounts = colSums(g.adtm)))
  } else {
    return(list(zeta=g.zeta,delta=g.delta,se=g.se,counts=g.counts,acounts=g.adtm))
  }
}

############## FIGHTIN' WORDS PLOTTING FUNCTION

# helper function
makeTransparent<-function(someColor, alpha=100)
{
  newColor<-col2rgb(someColor)
  apply(newColor, 2, function(curcoldata){rgb(red=curcoldata[1], green=curcoldata[2],
                                              blue=curcoldata[3],alpha=alpha, maxColorValue=255)})
}

fw.ggplot.groups <- function(fw.ch, groups.use = as.factor(rownames(fw.ch$zeta)), max.words = 50, max.countrank = 400, colorpalette=rep("black",length(groups.use)), sizescale=2, title="Comparison of Terms by Groups", subtitle = "", caption = "Group-specific terms are ordered by Fightin' Words statistic (Monroe, et al. 2008)") {
  if (is.null(dim(fw.ch$zeta))) {## two-group fw object consists of vectors, not matrices
    zetarankmat <- cbind(rank(-fw.ch$zeta),rank(fw.ch$zeta))
    colnames(zetarankmat) <- groups.use
    countrank <- rank(-(fw.ch$counts))
  } else {
    zetarankmat <- apply(-fw.ch$zeta[groups.use,],1,rank)
    countrank <- rank(-colSums(fw.ch$counts))
  }
  wideplotmat <- as_tibble(cbind(zetarankmat,countrank=countrank))
  wideplotmat$term=names(countrank)
  rankplot <- gather(wideplotmat, groups.use, zetarank, 1:ncol(zetarankmat))
  rankplot$plotsize <- sizescale*(50/(rankplot$zetarank))^(1/4)
  rankplot <- rankplot[rankplot$zetarank < max.words + 1 & rankplot$countrank<max.countrank+1,]
  rankplot$groups.use <- factor(rankplot$groups.use,levels=groups.use)
  
  p <- ggplot(rankplot, aes((nrow(rankplot)-countrank)^1, -(zetarank^1), colour=groups.use)) + 
    geom_point(show.legend=F,size=sizescale/2) + 
    theme_classic() +
    theme(axis.ticks=element_blank(), axis.text=element_blank() ) +
    ylim(-max.words,40) +
    facet_grid(groups.use ~ .) +
    geom_text_repel(aes(label = term), size = rankplot$plotsize, point.padding=.05,
                    box.padding = unit(0.20, "lines"), show.legend=F) +
    scale_colour_manual(values = alpha(colorpalette, .7)) + 
    labs(x=paste("Terms used more frequently overall -->"), y=paste("Terms used more frequently by group -->"),  title=title, subtitle=subtitle , caption = caption) 
  
}

fw.keys <- function(fw.ch,n.keys=10) {
  n.groups <- nrow(fw.ch$zeta)
  keys <- matrix("",n.keys,n.groups)
  colnames(keys) <- rownames(fw.ch$zeta)
  
  for (g in 1:n.groups) {
    keys[,g] <- names(sort(fw.ch$zeta[g,],dec=T)[1:n.keys])
  }
  keys
}

Compare Associated Press 1994-2010: Before and After “extremist”

Load and clean the data


######################################

### Text Cleaning Function

text_cleaner<-function(corpus){
  tempcorpus<-Corpus(VectorSource(corpus))
  tempcorpus<-tm_map(tempcorpus,
                    removePunctuation)
  tempcorpus<-tm_map(tempcorpus,
                    stripWhitespace)
  tempcorpus<-tm_map(tempcorpus,
                    removeNumbers)
  tempcorpus<-tm_map(tempcorpus,
                     removeWords, stopwords("english"))
  tempcorpus<-tm_map(tempcorpus, 
                    stemDocument)
  return(tempcorpus)
}

######################################

Calculate FW.

[1] 0.9900516

##################################################################

fw.extrem <- fwgroups(extrem_dtm, groups=extrem_NYT.dfm.long$Context)
Error: vector memory exhausted (limit reached?)

Get and show the top words per group by zeta.

##################################################################

fwkeys.extrem <- fw.keys(fw.extrem, n.keys=20)
cols <- rev(colnames(fwkeys.extrem))
fwkeys.extrem <- fwkeys.extrem[,cols]

##################################################################

kable(fwkeys.extrem)
Context.before Context.after
muslim group
jewish organ
rightw movement
islamic respons
member element
rrb hutu
suspect network
belong ideolog
ban militia
lrb oppos
alqaidalink view
small activ
rabin bomb
sunni sayyaf
assassin threaten
ap parti
alleg abu
outlaw attack
yitzhak alqaida
help govern

##################################################################

Plot: Comparing Words Before (in Blue), and After (in Red)

p.fw.extrem <- fw.ggplot.groups(fw.extrem,sizescale=4,max.words=200,
                                max.countrank=400,colorpalette=c("red","blue"),
                                 title = 'Comparison of Terms Before and After "Extremist"')
p.fw.extrem

Calculate Parts of speech by before and after

##################################################################

ud_model <- udpipe_load_model(ud_model$file_model)

txt <-as.character(extrem_NYT.dfm.long$context.text)

x_udp <- udpipe_annotate(ud_model, x = txt, doc_id = seq_along(txt))
x <- as.data.frame(x_udp)

x$doc_id <-as.integer(x$doc_id)


##################################################################
##################################################################

x_odd.before <- x[x$doc_id %% 2 == 1,]
x_even.after <-x[x$doc_id %% 2 == 0, ]

##################################################################

Bar Charts for Parts of Speech

Cooccurences

Cooccurences (part 2)


Corrs(x_odd.before)
Corrs(x_even.after)
NA

Extrem(ist) Fightin’ Words Over Time

library(tweenr)

TransitionTime2 <- ggproto(
  "TransitionTime2",
  TransitionTime,
  expand_panel = function (self, data, type, id, match, ease, enter, exit, params, 
                           layer_index) {
    row_time <- self$get_row_vars(data)
    if (is.null(row_time)) 
      return(data)
    data$group <- paste0(row_time$before, row_time$after)
    time <- as.integer(row_time$time)
    states <- split(data, time)
    times <- as.integer(names(states))
    nframes <- diff(times)
    nframes[1] <- nframes[1] + 1
    if (times[1] <= 1) {
      all_frames <- states[[1]]
      states <- states[-1]
    }
    else {
      all_frames <- data[0, , drop = FALSE]
      nframes <- c(times[1] - 1, nframes)
    }
    if (times[length(times)] < params$nframes) {
      states <- c(states, list(data[0, , drop = FALSE]))
      nframes <- c(nframes, params$nframes - times[length(times)])
    }
    for (i in seq_along(states)) {
      all_frames <- switch(type, point = tween_state(all_frames, 
                                                     states[[i]], ease, nframes[i], 
                                                     !!id, enter, exit), 
                           path = transform_path(all_frames, 
                                                 states[[i]], ease, nframes[i], 
                                                 !!id, enter, exit, match), 
                           polygon = transform_polygon(all_frames, 
                                                       states[[i]], ease, nframes[i], 
                                                       !!id, enter, exit, match), 
                           sf = transform_sf(all_frames, 
                                             states[[i]], ease, nframes[i], 
                                             !!id, enter, exit), 
                           stop(type, 
                                " layers not currently supported by transition_time", 
                                call. = FALSE))
    }
    true_frame <- seq(times[1], times[length(times)])
    all_frames <- all_frames[
      all_frames$.frame %in% 
        # which(true_frame > 0 & true_frame <= params$nframes),
        true_frame[which(true_frame > 0 & true_frame <= params$nframes)], # tweak line A
      , 
      drop = FALSE]
    # all_frames$.frame <- all_frames$.frame - min(all_frames$.frame) + 1 # remove line B
    all_frames$group <- paste0(all_frames$group, "<", all_frames$.frame, ">")
    all_frames$.frame <- NULL
    all_frames
  })

transition_time2 <- function (time, range = NULL) {
  time_quo <- enquo(time)
  gganimate:::require_quo(time_quo, "time")
  ggproto(NULL, TransitionTime2, 
          params = list(time_quo = time_quo, range = range))
}

home

LS0tCnRpdGxlOiAiRXh0cmVtKGlzdCkgRmlnaHRpbicgV29yZHMiCmF1dGhvcjogIkJyZWFubmEgRS4gR3JlZW4iCnN1YnRpdGxlOiAnQXNzb2NpYXRlZCBQcmVzcyAxOTk0LTIwMTA6IEtleXdvcmQ6IkV4dHJlbWlzdCInCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICAgIGRmX3ByaW50OiBwYWdlZAogIGh0bWxfbm90ZWJvb2s6CiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGRmX3ByaW50OiBwYWdlZAogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgdGhlbWU6IHVuaXRlZAogICAgdG9jOiB5ZXMKLS0tCgpbaG9tZV0oaHR0cHM6Ly9icmVncmVlbi5naXRodWIuaW8vKQoKIyMgTG9hZCBMaWJyYXJpZXMKCmBgYHtyIGxvYWQgbGlicmFyaWVzLCByZXN1bHRzPSdoaWRlJ30KCiMjIyBodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvdWRwaXBlL3ZpZ25ldHRlcy91ZHBpcGUtdXNlY2FzZS1wb3N0YWdnaW5nLWxlbW1hdGlzYXRpb24uaHRtbApsaWJyYXJ5KHVkcGlwZSkKdWRfbW9kZWwgPC0gdWRwaXBlX2Rvd25sb2FkX21vZGVsKGxhbmd1YWdlID0gImVuZ2xpc2giKQoKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnZ3JlcGVsKQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KHRtKQpsaWJyYXJ5KHF1YW50ZWRhKQpsaWJyYXJ5KGxhdHRpY2UpCmxpYnJhcnkobGF0dGljZUV4dHJhKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShwZHApCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKCmBgYAoKIyMgTG9hZCB0aGUgRlcgZnVuY3Rpb25zCgpgYGB7ciBsb2FkX2Z3X2Z1bmN0aW9uc30KCiMjIyBDT0RFIERJUkVDVExZIEZST006IGh0dHBzOi8vYnVydG1vbnJvZS5naXRodWIuaW8vVGV4dEFzRGF0YUNvdXJzZS9UdXRvcmlhbHMvVEFEQS1GaWdodGluV29yZHMubmIuaHRtbCMKZndncm91cHMgPC0gZnVuY3Rpb24oZHRtLCBncm91cHMsIHBhaXIgPSBOVUxMLCB3ZWlnaHRzID0gcmVwKDEsbnJvdyhkdG0pKSwgay5wcmlvciA9IC4xKSB7CiAgCiAgd2VpZ2h0c1tpcy5uYSh3ZWlnaHRzKV0gPC0gMAogIAogIHdlaWdodHMgPC0gd2VpZ2h0cy9tZWFuKHdlaWdodHMpCiAgCiAgemVyby5kb2MgPC0gcm93U3VtcyhkdG0pPT0wIHwgd2VpZ2h0cz09MAogIHplcm8udGVybSA8LSBjb2xTdW1zKGR0bVshemVyby5kb2MsXSk9PTAKICAKICBkdG0ubnogPC0gYXBwbHkoZHRtWyF6ZXJvLmRvYywhemVyby50ZXJtXSwyLCIqIiwgd2VpZ2h0c1shemVyby5kb2NdKQogIAogIGcucHJpb3IgPC0gdGNyb3NzcHJvZChyb3dTdW1zKGR0bS5ueiksY29sU3VtcyhkdG0ubnopKS9zdW0oZHRtLm56KQogIAogICMgCiAgCiAgZy5wb3N0ZXJpb3IgPC0gYXMubWF0cml4KGR0bS5ueiArIGsucHJpb3IqZy5wcmlvcikKICAKICBncm91cHMgPC0gZ3JvdXBzWyF6ZXJvLmRvY10KICBncm91cHMgPC0gZHJvcGxldmVscyhncm91cHMpCiAgCiAgZy5hZHRtIDwtIGFzLm1hdHJpeChhZ2dyZWdhdGUoeD1nLnBvc3RlcmlvcixieT1saXN0KGdyb3Vwcz1ncm91cHMpLEZVTj1zdW0pWywtMV0pCiAgcm93bmFtZXMoZy5hZHRtKSA8LSBsZXZlbHMoZ3JvdXBzKQogIAogIGcubGFkdG0gPC0gbG9nKGcuYWR0bSkKICAKICBnLmRlbHRhIDwtIHQoc2NhbGUoIHQoc2NhbGUoZy5sYWR0bSwgY2VudGVyPVQsIHNjYWxlPUYpKSwgY2VudGVyPVQsIHNjYWxlPUYpKQogIAogIGcuYWR0bV93IDwtIC1zd2VlcChnLmFkdG0sMSxyb3dTdW1zKGcuYWR0bSkpICMgdGVybXMgbm90IHcgc3Bva2VuIGJ5IGsKICBnLmFkdG1fayA8LSAtc3dlZXAoZy5hZHRtLDIsY29sU3VtcyhnLmFkdG0pKSAjIHcgc3Bva2VuIGJ5IGdyb3VwcyBvdGhlciB0aGFuIGsKICBnLmFkdG1fa3cgPC0gc3VtKGcuYWR0bSkgLSBnLmFkdG1fdyAtIGcuYWR0bV9rIC0gZy5hZHRtICMgdG90YWwgdGVybXMgbm90IHcgb3IgayAKICAKICBnLnNlIDwtIHNxcnQoMS9nLmFkdG0gKyAxL2cuYWR0bV93ICsgMS9nLmFkdG1fayArIDEvZy5hZHRtX2t3KQogIAogIGcuemV0YSA8LSBnLmRlbHRhL2cuc2UKICAKICBnLmNvdW50cyA8LSBhcy5tYXRyaXgoYWdncmVnYXRlKHg9ZHRtLm56LCBieSA9IGxpc3QoZ3JvdXBzPWdyb3VwcyksIEZVTj1zdW0pWywtMV0pCiAgCiAgaWYgKCFpcy5udWxsKHBhaXIpKSB7CiAgICBwci5kZWx0YSA8LSB0KHNjYWxlKCB0KHNjYWxlKGcubGFkdG1bcGFpcixdLCBjZW50ZXIgPSBULCBzY2FsZSA9RikpLCBjZW50ZXI9VCwgc2NhbGU9RikpCiAgICBwci5hZHRtX3cgPC0gLXN3ZWVwKGcuYWR0bVtwYWlyLF0sMSxyb3dTdW1zKGcuYWR0bVtwYWlyLF0pKQogICAgcHIuYWR0bV9rIDwtIC1zd2VlcChnLmFkdG1bcGFpcixdLDIsY29sU3VtcyhnLmFkdG1bcGFpcixdKSkgIyB3IHNwb2tlbiBieSBncm91cHMgb3RoZXIgdGhhbiBrCiAgICBwci5hZHRtX2t3IDwtIHN1bShnLmFkdG1bcGFpcixdKSAtIHByLmFkdG1fdyAtIHByLmFkdG1fayAtIGcuYWR0bVtwYWlyLF0gIyB0b3RhbCB0ZXJtcyBub3QgdyBvciBrCiAgICBwci5zZSA8LSBzcXJ0KDEvZy5hZHRtW3BhaXIsXSArIDEvcHIuYWR0bV93ICsgMS9wci5hZHRtX2sgKyAxL3ByLmFkdG1fa3cpCiAgICBwci56ZXRhIDwtIHByLmRlbHRhL3ByLnNlCiAgICAKICAgIHJldHVybihsaXN0KHpldGE9cHIuemV0YVsxLF0sIGRlbHRhPXByLmRlbHRhWzEsXSxzZT1wci5zZVsxLF0sIGNvdW50cyA9IGNvbFN1bXMoZHRtLm56KSwgYWNvdW50cyA9IGNvbFN1bXMoZy5hZHRtKSkpCiAgfSBlbHNlIHsKICAgIHJldHVybihsaXN0KHpldGE9Zy56ZXRhLGRlbHRhPWcuZGVsdGEsc2U9Zy5zZSxjb3VudHM9Zy5jb3VudHMsYWNvdW50cz1nLmFkdG0pKQogIH0KfQoKIyMjIyMjIyMjIyMjIyMgRklHSFRJTicgV09SRFMgUExPVFRJTkcgRlVOQ1RJT04KCiMgaGVscGVyIGZ1bmN0aW9uCm1ha2VUcmFuc3BhcmVudDwtZnVuY3Rpb24oc29tZUNvbG9yLCBhbHBoYT0xMDApCnsKICBuZXdDb2xvcjwtY29sMnJnYihzb21lQ29sb3IpCiAgYXBwbHkobmV3Q29sb3IsIDIsIGZ1bmN0aW9uKGN1cmNvbGRhdGEpe3JnYihyZWQ9Y3VyY29sZGF0YVsxXSwgZ3JlZW49Y3VyY29sZGF0YVsyXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJsdWU9Y3VyY29sZGF0YVszXSxhbHBoYT1hbHBoYSwgbWF4Q29sb3JWYWx1ZT0yNTUpfSkKfQoKZncuZ2dwbG90Lmdyb3VwcyA8LSBmdW5jdGlvbihmdy5jaCwgZ3JvdXBzLnVzZSA9IGFzLmZhY3Rvcihyb3duYW1lcyhmdy5jaCR6ZXRhKSksIG1heC53b3JkcyA9IDUwLCBtYXguY291bnRyYW5rID0gNDAwLCBjb2xvcnBhbGV0dGU9cmVwKCJibGFjayIsbGVuZ3RoKGdyb3Vwcy51c2UpKSwgc2l6ZXNjYWxlPTIsIHRpdGxlPSJDb21wYXJpc29uIG9mIFRlcm1zIGJ5IEdyb3VwcyIsIHN1YnRpdGxlID0gIiIsIGNhcHRpb24gPSAiR3JvdXAtc3BlY2lmaWMgdGVybXMgYXJlIG9yZGVyZWQgYnkgRmlnaHRpbicgV29yZHMgc3RhdGlzdGljIChNb25yb2UsIGV0IGFsLiAyMDA4KSIpIHsKICBpZiAoaXMubnVsbChkaW0oZncuY2gkemV0YSkpKSB7IyMgdHdvLWdyb3VwIGZ3IG9iamVjdCBjb25zaXN0cyBvZiB2ZWN0b3JzLCBub3QgbWF0cmljZXMKICAgIHpldGFyYW5rbWF0IDwtIGNiaW5kKHJhbmsoLWZ3LmNoJHpldGEpLHJhbmsoZncuY2gkemV0YSkpCiAgICBjb2xuYW1lcyh6ZXRhcmFua21hdCkgPC0gZ3JvdXBzLnVzZQogICAgY291bnRyYW5rIDwtIHJhbmsoLShmdy5jaCRjb3VudHMpKQogIH0gZWxzZSB7CiAgICB6ZXRhcmFua21hdCA8LSBhcHBseSgtZncuY2gkemV0YVtncm91cHMudXNlLF0sMSxyYW5rKQogICAgY291bnRyYW5rIDwtIHJhbmsoLWNvbFN1bXMoZncuY2gkY291bnRzKSkKICB9CiAgd2lkZXBsb3RtYXQgPC0gYXNfdGliYmxlKGNiaW5kKHpldGFyYW5rbWF0LGNvdW50cmFuaz1jb3VudHJhbmspKQogIHdpZGVwbG90bWF0JHRlcm09bmFtZXMoY291bnRyYW5rKQogIHJhbmtwbG90IDwtIGdhdGhlcih3aWRlcGxvdG1hdCwgZ3JvdXBzLnVzZSwgemV0YXJhbmssIDE6bmNvbCh6ZXRhcmFua21hdCkpCiAgcmFua3Bsb3QkcGxvdHNpemUgPC0gc2l6ZXNjYWxlKig1MC8ocmFua3Bsb3QkemV0YXJhbmspKV4oMS80KQogIHJhbmtwbG90IDwtIHJhbmtwbG90W3JhbmtwbG90JHpldGFyYW5rIDwgbWF4LndvcmRzICsgMSAmIHJhbmtwbG90JGNvdW50cmFuazxtYXguY291bnRyYW5rKzEsXQogIHJhbmtwbG90JGdyb3Vwcy51c2UgPC0gZmFjdG9yKHJhbmtwbG90JGdyb3Vwcy51c2UsbGV2ZWxzPWdyb3Vwcy51c2UpCiAgCiAgcCA8LSBnZ3Bsb3QocmFua3Bsb3QsIGFlcygobnJvdyhyYW5rcGxvdCktY291bnRyYW5rKV4xLCAtKHpldGFyYW5rXjEpLCBjb2xvdXI9Z3JvdXBzLnVzZSkpICsgCiAgICBnZW9tX3BvaW50KHNob3cubGVnZW5kPUYsc2l6ZT1zaXplc2NhbGUvMikgKyAKICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICB0aGVtZShheGlzLnRpY2tzPWVsZW1lbnRfYmxhbmsoKSwgYXhpcy50ZXh0PWVsZW1lbnRfYmxhbmsoKSApICsKICAgIHlsaW0oLW1heC53b3Jkcyw0MCkgKwogICAgZmFjZXRfZ3JpZChncm91cHMudXNlIH4gLikgKwogICAgZ2VvbV90ZXh0X3JlcGVsKGFlcyhsYWJlbCA9IHRlcm0pLCBzaXplID0gcmFua3Bsb3QkcGxvdHNpemUsIHBvaW50LnBhZGRpbmc9LjA1LAogICAgICAgICAgICAgICAgICAgIGJveC5wYWRkaW5nID0gdW5pdCgwLjIwLCAibGluZXMiKSwgc2hvdy5sZWdlbmQ9RikgKwogICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBhbHBoYShjb2xvcnBhbGV0dGUsIC43KSkgKyAKICAgIGxhYnMoeD1wYXN0ZSgiVGVybXMgdXNlZCBtb3JlIGZyZXF1ZW50bHkgb3ZlcmFsbCAtLT4iKSwgeT1wYXN0ZSgiVGVybXMgdXNlZCBtb3JlIGZyZXF1ZW50bHkgYnkgZ3JvdXAgLS0+IiksICB0aXRsZT10aXRsZSwgc3VidGl0bGU9c3VidGl0bGUgLCBjYXB0aW9uID0gY2FwdGlvbikgCiAgCn0KCmZ3LmtleXMgPC0gZnVuY3Rpb24oZncuY2gsbi5rZXlzPTEwKSB7CiAgbi5ncm91cHMgPC0gbnJvdyhmdy5jaCR6ZXRhKQogIGtleXMgPC0gbWF0cml4KCIiLG4ua2V5cyxuLmdyb3VwcykKICBjb2xuYW1lcyhrZXlzKSA8LSByb3duYW1lcyhmdy5jaCR6ZXRhKQogIAogIGZvciAoZyBpbiAxOm4uZ3JvdXBzKSB7CiAgICBrZXlzWyxnXSA8LSBuYW1lcyhzb3J0KGZ3LmNoJHpldGFbZyxdLGRlYz1UKVsxOm4ua2V5c10pCiAgfQogIGtleXMKfQpgYGAKCgojIyBDb21wYXJlIEFzc29jaWF0ZWQgUHJlc3MgMTk5NC0yMDEwOiBCZWZvcmUgYW5kIEFmdGVyICJleHRyZW1pc3QiCgoqTG9hZCBhbmQgY2xlYW4gdGhlIGRhdGEqCgogICogdG8gc3RyaW5nICYgbG93ZXIgdGV4dAogICogcGl2b3QgdG8gbG9uZyBmb3JtYXQKICAqIGFwcGx5IHRleHRfY2xlYW5lciB0byBvbmUgY29sdW1uICJjb250ZXh0LnRleHQiCgpgYGB7cn0KCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgojIyMgVGV4dCBDbGVhbmluZyBGdW5jdGlvbgoKdGV4dF9jbGVhbmVyPC1mdW5jdGlvbihjb3JwdXMpewogIHRlbXBjb3JwdXM8LUNvcnB1cyhWZWN0b3JTb3VyY2UoY29ycHVzKSkKICB0ZW1wY29ycHVzPC10bV9tYXAodGVtcGNvcnB1cywKICAgICAgICAgICAgICAgICAgICByZW1vdmVQdW5jdHVhdGlvbikKICB0ZW1wY29ycHVzPC10bV9tYXAodGVtcGNvcnB1cywKICAgICAgICAgICAgICAgICAgICBzdHJpcFdoaXRlc3BhY2UpCiAgdGVtcGNvcnB1czwtdG1fbWFwKHRlbXBjb3JwdXMsCiAgICAgICAgICAgICAgICAgICAgcmVtb3ZlTnVtYmVycykKICB0ZW1wY29ycHVzPC10bV9tYXAodGVtcGNvcnB1cywKICAgICAgICAgICAgICAgICAgICAgcmVtb3ZlV29yZHMsIHN0b3B3b3JkcygiZW5nbGlzaCIpKQogIHRlbXBjb3JwdXM8LXRtX21hcCh0ZW1wY29ycHVzLCAKICAgICAgICAgICAgICAgICAgICBzdGVtRG9jdW1lbnQpCiAgcmV0dXJuKHRlbXBjb3JwdXMpCn0KCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpgYGAKCmBgYHtyIGNsZWFuX3RleHQsIGVjaG89RkFMU0UsIHJlc3VsdHM9IEZBTFNFfQoKZXh0cmVtX0FQLmRmbSA8LSByZWFkLmRlbGltKCJleHRyZW1pc3RfOTQxMF9BUC50eHQiLCBoZWFkZXIgPSBUUlVFLCBzZXAgPSAiXHQiKQpleHRyZW1fQVAuZGZtJHB1YmRhdGUgPSBzdWJzdHIoZXh0cmVtX0FQLmRmbSRUZXh0LklELDksMTYpCmV4dHJlbV9BUC5kZm0kcHViZGF0ZSA8LSBhcy5QT1NJWGN0KGV4dHJlbV9BUC5kZm0kcHViZGF0ZSwgZm9ybWF0ID0gIiVZJW0lZCIpCmV4dHJlbV9BUC5kZm0kcHViZGF0ZSA8LSBhcy5EYXRlKGV4dHJlbV9BUC5kZm0kcHViZGF0ZSwgZm9ybWF0PSIlWS0lbS0lZCIpCmV4dHJlbV9BcC5kZm0kcHVieWVhciA8LSB5ZWFyKGV4dHJlbV9BUC5kZm0kcHViZGF0ZSkKCiMgZXh0cmVtX05ZVC5kZm0kQ29udGV4dC5iZWZvcmUgPSBsYXBwbHkoZXh0cmVtX05ZVC5kZm0kQ29udGV4dC5iZWZvcmUsIHRvU3RyaW5nKQojIGV4dHJlbV9OWVQuZGZtJENvbnRleHQuYmVmb3JlID0gbGFwcGx5KGV4dHJlbV9OWVQuZGZtJENvbnRleHQuYmVmb3JlLCB0b2xvd2VyKQojIAojIGV4dHJlbV9OWVQuZGZtJENvbnRleHQuYWZ0ZXIgPSBsYXBwbHkoZXh0cmVtX05ZVC5kZm0kQ29udGV4dC5hZnRlciwgdG9TdHJpbmcpCiMgZXh0cmVtX05ZVC5kZm0kQ29udGV4dC5hZnRlciA9IGxhcHBseShleHRyZW1fTllULmRmbSRDb250ZXh0LmFmdGVyLCB0b2xvd2VyKQoKZXh0cmVtX0FQLmRmbSA8LSBleHRyZW1fQVAuZGZtICU+JSBkaXN0aW5jdChDb250ZXh0LmJlZm9yZSwgLmtlZXBfYWxsID0gVFJVRSkKCmV4dHJlbV9BUC5kZm0ubG9uZyA8LSBwaXZvdF9sb25nZXIoZXh0cmVtX0FQLmRmbSwgY29scz1jKENvbnRleHQuYmVmb3JlLCBDb250ZXh0LmFmdGVyKSwgbmFtZXNfdG8gPSAiQ29udGV4dCIsIHZhbHVlc190byA9ICJjb250ZXh0LnRleHQiKQoKZXh0cmVtX0FQLmRmbS5sb25nJENvbnRleHQgPC0gYXMuZmFjdG9yKGV4dHJlbV9BUC5kZm0ubG9uZyRDb250ZXh0KQoKZXh0cmVtZWNvcnB1cyA8LXRleHRfY2xlYW5lcihleHRyZW1fQVAuZGZtLmxvbmckY29udGV4dC50ZXh0KQoKYGBgCgoKQ2FsY3VsYXRlIEZXLgoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIGVjaG89RkFMU0V9CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwplIDwtIGRmbShleHRyZW1lY29ycHVzJGNvbnRlbnQpCm1lc3NhZ2UoZGltKGUpKQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgplIDwtIGRmbV9zZWxlY3QoZSwgcGF0dGVybiA9IHN0b3B3b3JkcygiZW5nbGlzaCIpLCBzZWxlY3Rpb24gPSAicmVtb3ZlIikKZSA8LSBkZm1fc2VsZWN0KGUsIG1pbl9uY2hhciA9IDIpCmUgPC0gZGZtX3RyaW0oZSwgbWluX3Rlcm1mcmVxID0gMTAwLCBtaW5fZG9jZnJlcSA9IC4wNSwgdmVyYm9zZT1UUlVFKQoKbWVzc2FnZShkaW0oZSkpCm1lc3NhZ2Uoc3BhcnNpdHkoZSkpCnNwYXJzaXR5KGUpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCmV4dHJlbV9kdG0gPC0gY29udmVydChlLCB0bz0nZGF0YS5mcmFtZScpCmV4dHJlbV9kdG0gPC0gZXh0cmVtX2R0bVstYygxKV0KdyA8LSB3aGljaCggc2FwcGx5KGV4dHJlbV9kdG0sIGNsYXNzICkgPT0gJ2NoYXJhY3RlcicgKQoKYGBgCgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgZWNobz1UUlVFfQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpmdy5leHRyZW0gPC0gZndncm91cHMoZXh0cmVtX2R0bSwgZ3JvdXBzPWV4dHJlbV9BUC5kZm0ubG9uZyRDb250ZXh0KQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgptZXNzYWdlKHJtKGV4dHJlbV9kdG0pKQptZXNzYWdlKHJtKGUpKQoKYGBgCgoKR2V0IGFuZCBzaG93IHRoZSB0b3Agd29yZHMgcGVyIGdyb3VwIGJ5IHpldGEuCgpgYGB7ciBlY2hvPVRSVUV9CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKZndrZXlzLmV4dHJlbSA8LSBmdy5rZXlzKGZ3LmV4dHJlbSwgbi5rZXlzPTIwKQpjb2xzIDwtIHJldihjb2xuYW1lcyhmd2tleXMuZXh0cmVtKSkKZndrZXlzLmV4dHJlbSA8LSBmd2tleXMuZXh0cmVtWyxjb2xzXQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgprYWJsZShmd2tleXMuZXh0cmVtKQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpgYGAKCipQbG90OiBDb21wYXJpbmcgV29yZHMgQmVmb3JlIChpbiBCbHVlKSwgYW5kIEFmdGVyIChpbiBSZWQpKgoKYGBge3IsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTR9CnAuZncuZXh0cmVtIDwtIGZ3LmdncGxvdC5ncm91cHMoZncuZXh0cmVtLHNpemVzY2FsZT00LG1heC53b3Jkcz0yMDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4LmNvdW50cmFuaz00MDAsY29sb3JwYWxldHRlPWMoInJlZCIsImJsdWUiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSAnQ29tcGFyaXNvbiBvZiBUZXJtcyBCZWZvcmUgYW5kIEFmdGVyICJFeHRyZW1pc3QiJykKcC5mdy5leHRyZW0KCmBgYAoKIyMgQ2FsY3VsYXRlIFBhcnRzIG9mIHNwZWVjaCBieSBiZWZvcmUgYW5kIGFmdGVyCgpgYGB7ciwgcmVzdWx0cz0naGlkZSd9CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKdWRfbW9kZWwgPC0gdWRwaXBlX2xvYWRfbW9kZWwodWRfbW9kZWwkZmlsZV9tb2RlbCkKCnR4dCA8LWFzLmNoYXJhY3RlcihleHRyZW1fQVAuZGZtLmxvbmckY29udGV4dC50ZXh0KQoKeF91ZHAgPC0gdWRwaXBlX2Fubm90YXRlKHVkX21vZGVsLCB4ID0gdHh0LCBkb2NfaWQgPSBzZXFfYWxvbmcodHh0KSkKeCA8LSBhcy5kYXRhLmZyYW1lKHhfdWRwKQoKeCRkb2NfaWQgPC1hcy5pbnRlZ2VyKHgkZG9jX2lkKQoKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKCmBgYAoKYGBge3IsIHJlc3VsdHM9J2hpZGUnfQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCnhfb2RkLmJlZm9yZSA8LSB4W3gkZG9jX2lkICUlIDIgPT0gMSxdCnhfZXZlbi5hZnRlciA8LXhbeCRkb2NfaWQgJSUgMiA9PSAwLCBdCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCmBgYAoKYGBge3IgYmFyY2hhcnRmdW5jdHMsIGVjaG89RkFMU0V9CgojIyBVTklWRVJTQUwgUG9TClVQT1NfYmFyY2hhcnQgPC0gZnVuY3Rpb24oZGYxLCBkZjIpewogIAogIHN0YXRzMSA8LSB0eHRfZnJlcShkZjEkdXBvcykKICBzdGF0czEka2V5IDwtIGZhY3RvcihzdGF0czEka2V5LCBsZXZlbHMgPSByZXYoc3RhdHMxJGtleSkpCiAgCiAgc3RhdHMyIDwtIHR4dF9mcmVxKGRmMiR1cG9zKQogIHN0YXRzMiRrZXkgPC0gZmFjdG9yKHN0YXRzMiRrZXksIGxldmVscyA9IHJldihzdGF0czIka2V5KSkKICAKICBjKGJhcmNoYXJ0KGtleSB+IGZyZXEsIGRhdGEgPSBzdGF0czEsIGNvbCA9ICJjYWRldGJsdWUiLCAKICAgICAgICBtYWluID0gIlVQT1MgKFVuaXZlcnNhbCBQYXJ0cyBvZiBTcGVlY2gpXG4gZnJlcXVlbmN5IG9mIG9jY3VycmVuY2U6IEJFRk9SRSB2cyBBRlRFUiIsIAogICAgICAgICB4bGFiID0gIkZyZXEiKSwgCiAgICBiYXJjaGFydChrZXkgfiBmcmVxLCBkYXRhID0gc3RhdHMyLCBjb2wgPSAgJ3NreWJsdWUnLAogICAgICAgICB4bGFiID0gIkZyZXEiKSkKCn0KCgojIyBOT1VOUwpOT1VOU19iYXJjaGFydCA8LSBmdW5jdGlvbihkZjEsIGRmMil7CiAgCiAgc3RhdHMxIDwtIHN1YnNldChkZjEsIHVwb3MgJWluJSBjKCJOT1VOIikpIAogIHN0YXRzMSA8LSB0eHRfZnJlcShzdGF0czEkdG9rZW4pCiAgc3RhdHMxJGtleSA8LSBmYWN0b3Ioc3RhdHMxJGtleSwgbGV2ZWxzID0gcmV2KHN0YXRzMSRrZXkpKQogIAogIHN0YXRzMiA8LSBzdWJzZXQoZGYyLCB1cG9zICVpbiUgYygiTk9VTiIpKSAKICBzdGF0czIgPC0gdHh0X2ZyZXEoc3RhdHMyJHRva2VuKQogIHN0YXRzMiRrZXkgPC0gZmFjdG9yKHN0YXRzMiRrZXksIGxldmVscyA9IHJldihzdGF0czIka2V5KSkKICAKICBjKGJhcmNoYXJ0KGtleSB+IGZyZXEsIGRhdGEgPSBoZWFkKHN0YXRzMSwgMjApLCBjb2wgPSAiY2FkZXRibHVlIiwgCiAgICAgICAgICAgbWFpbiA9ICJNb3N0IG9jY3VycmluZyBub3VuczogQkVGT1JFIHZzIEFGVEVSIiwgeGxhYiA9ICJGcmVxIiksCiAgICAgIGJhcmNoYXJ0KGtleSB+IGZyZXEsIGRhdGEgPSBoZWFkKHN0YXRzMiwgMjApLCBjb2wgPSAic2t5Ymx1ZSIsIAogICAgICAgICAgICB4bGFiID0gIkZyZXEiKSkKfQoKIyMgQURKRUNUSVZFUwpBREpfYmFyY2hhcnQgPC0gZnVuY3Rpb24oZGYxLCBkZjIpewogIAogIHN0YXRzMSA8LSBzdWJzZXQoZGYxLCB1cG9zICVpbiUgYygiQURKIikpIAogIHN0YXRzMSA8LSB0eHRfZnJlcShzdGF0czEkdG9rZW4pCiAgc3RhdHMxJGtleSA8LSBmYWN0b3Ioc3RhdHMxJGtleSwgbGV2ZWxzID0gcmV2KHN0YXRzMSRrZXkpKQogIAogIHN0YXRzMiA8LSBzdWJzZXQoZGYyLCB1cG9zICVpbiUgYygiQURKIikpIAogIHN0YXRzMiA8LSB0eHRfZnJlcShzdGF0czIkdG9rZW4pCiAgc3RhdHMyJGtleSA8LSBmYWN0b3Ioc3RhdHMyJGtleSwgbGV2ZWxzID0gcmV2KHN0YXRzMiRrZXkpKQogIAogIGMoYmFyY2hhcnQoa2V5IH4gZnJlcSwgZGF0YSA9IGhlYWQoc3RhdHMxLCAyMCksIGNvbCA9ICJjYWRldGJsdWUiLCAKICAgICAgICAgICBtYWluID0gIk1vc3Qgb2NjdXJyaW5nIGFkamVjdGl2ZXM6IEJFRk9SRSB2cyBBRlRFUiIsIHhsYWIgPSAiRnJlcSIpLAogICAgICBiYXJjaGFydChrZXkgfiBmcmVxLCBkYXRhID0gaGVhZChzdGF0czIsIDIwKSwgY29sID0gInNreWJsdWUiLCAKICAgICAgICAgeGxhYiA9ICJGcmVxIikpCn0KCiMjIFVzaW5nIFJBS0UgdG8gZmluZCBrZXl3b3JkcwpSQUtFX0tXX2JhcmNoYXJ0IDwtIGZ1bmN0aW9uKGRmMSxkZjIpewogIAogIHN0YXRzMSA8LSBrZXl3b3Jkc19yYWtlKHggPSBkZjEsIHRlcm0gPSAibGVtbWEiLCBncm91cCA9ICJkb2NfaWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHJlbGV2YW50ID0gZGYxJHVwb3MgJWluJSBjKCJOT1VOIiwgIkFESiIpKQogIHN0YXRzMSRrZXkgPC0gZmFjdG9yKHN0YXRzMSRrZXl3b3JkLCBsZXZlbHMgPSByZXYoc3RhdHMxJGtleXdvcmQpKQogIAogIHN0YXRzMiA8LSBrZXl3b3Jkc19yYWtlKHggPSBkZjIsIHRlcm0gPSAibGVtbWEiLCBncm91cCA9ICJkb2NfaWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHJlbGV2YW50ID0gZGYyJHVwb3MgJWluJSBjKCJOT1VOIiwgIkFESiIpKQogIHN0YXRzMiRrZXkgPC0gZmFjdG9yKHN0YXRzMiRrZXl3b3JkLCBsZXZlbHMgPSByZXYoc3RhdHMyJGtleXdvcmQpKQogIAogIAogIGMoYmFyY2hhcnQoa2V5IH4gcmFrZSwgZGF0YSA9IGhlYWQoc3Vic2V0KHN0YXRzMSwgZnJlcSA+IDMpLCAyMCksIGNvbCA9ICJjYWRldGJsdWUiLCAKICAgICAgICAgICBtYWluID0gIktleXdvcmRzIGlkZW50aWZpZWQgYnkgUkFLRTogQkVGT1JFIHZzIEFGVEVSIiwgCiAgICAgICAgICAgeGxhYiA9ICJSYWtlIiksCiAgICBiYXJjaGFydChrZXkgfiByYWtlLCBkYXRhID0gaGVhZChzdWJzZXQoc3RhdHMyLCBmcmVxID4gMyksIDIwKSwgY29sID0gInNreWJsdWUiLCAKICAgICAgICAgICB4bGFiID0gIlJha2UiKSkKfQoKIyMgVXNpbmcgUG9pbnR3aXNlIE11dHVhbCBJbmZvcm1hdGlvbiBDb2xsb2NhdGlvbnMKUFdJX2JhcmNoYXJ0IDwtIGZ1bmN0aW9uKGRmMSwgZGYyKXsKICAKICBkZjEkd29yZCA8LSB0b2xvd2VyKGRmMSR0b2tlbikKICBzdGF0czEgPC0ga2V5d29yZHNfY29sbG9jYXRpb24oeCA9IGRmMSwgdGVybSA9ICJ3b3JkIiwgZ3JvdXAgPSAiZG9jX2lkIikKICBzdGF0czEka2V5IDwtIGZhY3RvcihzdGF0czEka2V5d29yZCwgbGV2ZWxzID0gcmV2KHN0YXRzMSRrZXl3b3JkKSkKICAKICBkZjIkd29yZCA8LSB0b2xvd2VyKGRmMiR0b2tlbikKICBzdGF0czIgPC0ga2V5d29yZHNfY29sbG9jYXRpb24oeCA9IGRmMiwgdGVybSA9ICJ3b3JkIiwgZ3JvdXAgPSAiZG9jX2lkIikKICBzdGF0czIka2V5IDwtIGZhY3RvcihzdGF0czIka2V5d29yZCwgbGV2ZWxzID0gcmV2KHN0YXRzMiRrZXl3b3JkKSkKICAKICBjKGJhcmNoYXJ0KGtleSB+IHBtaSwgZGF0YSA9IGhlYWQoc3Vic2V0KHN0YXRzMSwgZnJlcSA+IDMpLCAyMCksIGNvbCA9ICJjYWRldGJsdWUiLCAKICAgICAgICAgICBtYWluID0gIktleXdvcmRzIGlkZW50aWZpZWQgYnkgUE1JIENvbGxvY2F0aW9uOiBCRUZPUkUgdnMgQUZURVIiLCAKICAgICAgICAgICB4bGFiID0gIlBNSSAoUG9pbnR3aXNlIE11dHVhbCBJbmZvcm1hdGlvbikiKSwKICAgICAgYmFyY2hhcnQoa2V5IH4gcG1pLCBkYXRhID0gaGVhZChzdWJzZXQoc3RhdHMyLCBmcmVxID4gMyksIDIwKSwgY29sID0gInNreWJsdWUiLCAKICAgICAgICAgICB4bGFiID0gIlBNSSAoUG9pbnR3aXNlIE11dHVhbCBJbmZvcm1hdGlvbikiKSkKfQoKIyMgVXNpbmcgYSBzZXF1ZW5jZSBvZiBQT1MgdGFncyAobm91biBwaHJhc2VzIC8gdmVyYiBwaHJhc2VzKQpQT1NfYmFyY2hhcnQgPC0gZnVuY3Rpb24oZGYxLCBkZjIpewogIAogIGRmMSRwaHJhc2VfdGFnIDwtIGFzX3BocmFzZW1hY2hpbmUoZGYxJHVwb3MsIHR5cGUgPSAidXBvcyIpCiAgc3RhdHMxIDwtIGtleXdvcmRzX3BocmFzZXMoeCA9IGRmMSRwaHJhc2VfdGFnLCB0ZXJtID0gdG9sb3dlcihkZjEkdG9rZW4pLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiKEF8TikqTihQK0QqKEF8TikqTikqIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpc19yZWdleCA9IFRSVUUsIGRldGFpbGVkID0gRkFMU0UpCiAgc3RhdHMxIDwtIHN1YnNldChzdGF0czEsIG5ncmFtID4gMSAmIGZyZXEgPiAzKQogIHN0YXRzMSRrZXkgPC0gZmFjdG9yKHN0YXRzMSRrZXl3b3JkLCBsZXZlbHMgPSByZXYoc3RhdHMxJGtleXdvcmQpKQogIAogIGRmMiRwaHJhc2VfdGFnIDwtIGFzX3BocmFzZW1hY2hpbmUoZGYyJHVwb3MsIHR5cGUgPSAidXBvcyIpCiAgc3RhdHMyIDwtIGtleXdvcmRzX3BocmFzZXMoeCA9IGRmMiRwaHJhc2VfdGFnLCB0ZXJtID0gdG9sb3dlcihkZjIkdG9rZW4pLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiKEF8TikqTihQK0QqKEF8TikqTikqIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpc19yZWdleCA9IFRSVUUsIGRldGFpbGVkID0gRkFMU0UpCiAgc3RhdHMyIDwtIHN1YnNldChzdGF0czIsIG5ncmFtID4gMSAmIGZyZXEgPiAzKQogIHN0YXRzMiRrZXkgPC0gZmFjdG9yKHN0YXRzMiRrZXl3b3JkLCBsZXZlbHMgPSByZXYoc3RhdHMyJGtleXdvcmQpKQogIAogIGMoYmFyY2hhcnQoa2V5IH4gZnJlcSwgZGF0YSA9IGhlYWQoc3RhdHMxLCAyMCksIGNvbCA9ICJjYWRldGJsdWUiLCAKICAgICAgICAgICBtYWluID0gIktleXdvcmRzIC0gc2ltcGxlIG5vdW4gcGhyYXNlczogQkVGT1JFIHZzIEFGVEVSIiwgeGxhYiA9ICJGcmVxdWVuY3kiKSwKICAgICAgYmFyY2hhcnQoa2V5IH4gZnJlcSwgZGF0YSA9IGhlYWQoc3RhdHMyLCAyMCksIGNvbCA9ICJza3libHVlIiwgCiAgICAgICAgICAgICAgIHhsYWIgPSAiRnJlcXVlbmN5IikpCn0KYGBgCgoKIyMgQmFyIENoYXJ0cyBmb3IgUGFydHMgb2YgU3BlZWNoIAoKYGBge3IgUE9TYmFyY2hhcnRzLCBlY2hvPUZBTFNFLCBmaWcud2lkdGg9OH0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpVUE9TX2JhcmNoYXJ0KHhfb2RkLmJlZm9yZSwgeF9ldmVuLmFmdGVyKQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpOT1VOU19iYXJjaGFydCh4X29kZC5iZWZvcmUsIHhfZXZlbi5hZnRlcikKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKQURKX2JhcmNoYXJ0KHhfb2RkLmJlZm9yZSwgeF9ldmVuLmFmdGVyKQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpSQUtFX0tXX2JhcmNoYXJ0KHhfb2RkLmJlZm9yZSwgeF9ldmVuLmFmdGVyKQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpQV0lfYmFyY2hhcnQoeF9vZGQuYmVmb3JlLCB4X2V2ZW4uYWZ0ZXIpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKClBPU19iYXJjaGFydCh4X29kZC5iZWZvcmUsIHhfZXZlbi5hZnRlcikKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpgYGAKCgojIyBDb29jY3VyZW5jZXMKCmBgYHtyLCBlY2hvPUZBTFNFLCBmaWcud2lkdGg9Nn0KCkNPX09DX25vdW5fYWRqX3NhbWVfc2VudC5iZWZvcmUgPC0gZnVuY3Rpb24oZGYxKXsKICAKICBsaWJyYXJ5KGlncmFwaCkKICBsaWJyYXJ5KGdncmFwaCkKICBsaWJyYXJ5KGdncGxvdDIpCiAgCiAgY29vYyA8LSBjb29jY3VycmVuY2UoeCA9IHN1YnNldChkZjEsIHVwb3MgJWluJSBjKCJOT1VOIiwgIkFESiIpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgdGVybSA9ICJsZW1tYSIsIAogICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gYygiZG9jX2lkIiwgInBhcmFncmFwaF9pZCIsICJzZW50ZW5jZV9pZCIpKQoKICB3b3JkbmV0d29yayA8LSBoZWFkKGNvb2MsIDYwKQogIHdvcmRuZXR3b3JrIDwtIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSh3b3JkbmV0d29yaykKICAKICBnZ3JhcGgod29yZG5ldHdvcmssIGxheW91dCA9ICJmciIpICsKICAgIGdlb21fZWRnZV9saW5rKGFlcyh3aWR0aCA9IGNvb2MsIGVkZ2VfYWxwaGEgPSBjb29jKSwgZWRnZV9jb2xvdXIgPSAicGluayIpICsKICAgIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IG5hbWUpLCBjb2wgPSAiZGFya2dyZWVuIiwgc2l6ZSA9IDQpICsKICAgIHRoZW1lX2dyYXBoKGJhc2VfZmFtaWx5ID0gIkFyaWFsIE5hcnJvdyIpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogICAgbGFicyh0aXRsZSA9ICJDb29jY3VycmVuY2VzIHdpdGhpbiBzZW50ZW5jZTogQkVGT1JFIiwgc3VidGl0bGUgPSAiTm91bnMgJiBBZGplY3RpdmUiKQogIAp9CgpDT19PQ19ub3VuX2Fkal9zYW1lX3NlbnQuYWZ0ZXIgPC0gZnVuY3Rpb24oZGYyKXsKICAKICBsaWJyYXJ5KGlncmFwaCkKICBsaWJyYXJ5KGdncmFwaCkKICBsaWJyYXJ5KGdncGxvdDIpCiAgCiAgY29vYyA8LSBjb29jY3VycmVuY2UoeCA9IHN1YnNldChkZjIsIHVwb3MgJWluJSBjKCJOT1VOIiwgIkFESiIpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgdGVybSA9ICJsZW1tYSIsIAogICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gYygiZG9jX2lkIiwgInBhcmFncmFwaF9pZCIsICJzZW50ZW5jZV9pZCIpKQoKICB3b3JkbmV0d29yayA8LSBoZWFkKGNvb2MsIDYwKQogIHdvcmRuZXR3b3JrIDwtIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSh3b3JkbmV0d29yaykKICAKICBnZ3JhcGgod29yZG5ldHdvcmssIGxheW91dCA9ICJmciIpICsKICAgIGdlb21fZWRnZV9saW5rKGFlcyh3aWR0aCA9IGNvb2MsIGVkZ2VfYWxwaGEgPSBjb29jKSwgZWRnZV9jb2xvdXIgPSAibGlnaHRncmVlbiIpICsKICAgIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IG5hbWUpLCBjb2wgPSAiZGFya2JsdWUiLCBzaXplID0gNCkgKwogICAgdGhlbWVfZ3JhcGgoYmFzZV9mYW1pbHkgPSAiQXJpYWwgTmFycm93IikgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgICBsYWJzKHRpdGxlID0gIkNvb2NjdXJyZW5jZXMgd2l0aGluIHNlbnRlbmNlOiBBRlRFUiIsIHN1YnRpdGxlID0gIk5vdW5zICYgQWRqZWN0aXZlIikKICAKfQoKCkNPX09DX25vdW5fYWRqX3NhbWVfc2VudC5iZWZvcmUoeF9vZGQuYmVmb3JlKQpDT19PQ19ub3VuX2Fkal9zYW1lX3NlbnQuYWZ0ZXIoeF9ldmVuLmFmdGVyKQoKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKQ09fT0Nfbm91bl9hZGpfZm9sbG93aW5nLmJlZm9yZSA8LSBmdW5jdGlvbihkZil7CiAgY29vYyA8LSBjb29jY3VycmVuY2UoZGYkbGVtbWEsIHJlbGV2YW50ID0gZGYkdXBvcyAlaW4lIGMoIk5PVU4iLCAiQURKIiksIHNraXBncmFtID0gMSkKICBoZWFkKGNvb2MpCiAgCiAgd29yZG5ldHdvcmsgPC0gaGVhZChjb29jLCA2MCkKICB3b3JkbmV0d29yayA8LSBncmFwaF9mcm9tX2RhdGFfZnJhbWUod29yZG5ldHdvcmspCiAgZ2dyYXBoKHdvcmRuZXR3b3JrLCBsYXlvdXQgPSAiZnIiKSArCiAgICBnZW9tX2VkZ2VfbGluayhhZXMod2lkdGggPSBjb29jLCBlZGdlX2FscGhhID0gY29vYyksIGVkZ2VfY29sb3VyID0gImxpZ2h0Z3JlZW4iKSArCiAgICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBuYW1lKSwgY29sID0gImRhcmtncmVlbiIsIHNpemUgPSA0KSArCiAgICB0aGVtZV9ncmFwaChiYXNlX2ZhbWlseSA9ICJBcmlhbCBOYXJyb3ciKSArCiAgICBsYWJzKHRpdGxlID0gIldvcmRzIGZvbGxvd2luZyBvbmUgYW5vdGhlcjogQkVGT1JFIiwgc3VidGl0bGUgPSAiTm91bnMgJiBBZGplY3RpdmUiKQp9CgpDT19PQ19ub3VuX2Fkal9mb2xsb3dpbmcuYWZ0ZXIgPC0gZnVuY3Rpb24oZGYpewogIGNvb2MgPC0gY29vY2N1cnJlbmNlKGRmJGxlbW1hLCByZWxldmFudCA9IGRmJHVwb3MgJWluJSBjKCJOT1VOIiwgIkFESiIpLCBza2lwZ3JhbSA9IDEpCiAgaGVhZChjb29jKQogIAogIHdvcmRuZXR3b3JrIDwtIGhlYWQoY29vYywgNjApCiAgd29yZG5ldHdvcmsgPC0gZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKHdvcmRuZXR3b3JrKQogIGdncmFwaCh3b3JkbmV0d29yaywgbGF5b3V0ID0gImZyIikgKwogICAgZ2VvbV9lZGdlX2xpbmsoYWVzKHdpZHRoID0gY29vYywgZWRnZV9hbHBoYSA9IGNvb2MpLCBlZGdlX2NvbG91ciA9ICJza3libHVlIikgKwogICAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFtZSksIGNvbCA9ICJkYXJrYmx1ZSIsIHNpemUgPSA0KSArCiAgICB0aGVtZV9ncmFwaChiYXNlX2ZhbWlseSA9ICJBcmlhbCBOYXJyb3ciKSArCiAgICBsYWJzKHRpdGxlID0gIldvcmRzIGZvbGxvd2luZyBvbmUgYW5vdGhlcjogQUZURVIiLCBzdWJ0aXRsZSA9ICJOb3VucyAmIEFkamVjdGl2ZSIpCn0KCgpDT19PQ19ub3VuX2Fkal9mb2xsb3dpbmcuYmVmb3JlKHhfb2RkLmJlZm9yZSkKQ09fT0Nfbm91bl9hZGpfZm9sbG93aW5nLmFmdGVyKHhfZXZlbi5hZnRlcikKCmBgYAoKCgojIyBDb29jY3VyZW5jZXMgKHBhcnQgMikKCmBgYHtyLCBlY2hvPUZBTFNFfQoKQ29ycnMgPC0gZnVuY3Rpb24oZGYpewogIGRmJGlkIDwtIHVuaXF1ZV9pZGVudGlmaWVyKGRmLCBmaWVsZHMgPSBjKCJzZW50ZW5jZV9pZCIsICJkb2NfaWQiKSkKICBkdG0gPC0gc3Vic2V0KGRmLCB1cG9zICVpbiUgYygiTk9VTiIsICJBREoiKSkKICBkdG0gPC0gZG9jdW1lbnRfdGVybV9mcmVxdWVuY2llcyhkdG0sIGRvY3VtZW50ID0gImlkIiwgdGVybSA9ICJsZW1tYSIpCiAgZHRtIDwtIGRvY3VtZW50X3Rlcm1fbWF0cml4KGR0bSkKICBkdG0gPC0gZHRtX3JlbW92ZV9sb3dmcmVxKGR0bSwgbWluZnJlcSA9IDUpCiAgdGVybWNvcnJlbGF0aW9ucyA8LSBkdG1fY29yKGR0bSkKICB5IDwtIGFzX2Nvb2NjdXJyZW5jZSh0ZXJtY29ycmVsYXRpb25zKQogIHkgPC0gc3Vic2V0KHksIHRlcm0xIDwgdGVybTIgJiBhYnMoY29vYykgPiAwLjIpCiAgeSA8LSB5W29yZGVyKGFicyh5JGNvb2MpLCBkZWNyZWFzaW5nID0gVFJVRSksIF0KICB5WzE6MjUsXQp9CgpgYGAKCmBgYHtyfQoKQ29ycnMoeF9vZGQuYmVmb3JlKQpDb3Jycyh4X2V2ZW4uYWZ0ZXIpCgpgYGAKCgojIEV4dHJlbShpc3QpIEZpZ2h0aW4nIFdvcmRzIE92ZXIgVGltZQpgYGB7cn0KbGlicmFyeSh0d2VlbnIpCgpUcmFuc2l0aW9uVGltZTIgPC0gZ2dwcm90bygKICAiVHJhbnNpdGlvblRpbWUyIiwKICBUcmFuc2l0aW9uVGltZSwKICBleHBhbmRfcGFuZWwgPSBmdW5jdGlvbiAoc2VsZiwgZGF0YSwgdHlwZSwgaWQsIG1hdGNoLCBlYXNlLCBlbnRlciwgZXhpdCwgcGFyYW1zLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgbGF5ZXJfaW5kZXgpIHsKICAgIHJvd190aW1lIDwtIHNlbGYkZ2V0X3Jvd192YXJzKGRhdGEpCiAgICBpZiAoaXMubnVsbChyb3dfdGltZSkpIAogICAgICByZXR1cm4oZGF0YSkKICAgIGRhdGEkZ3JvdXAgPC0gcGFzdGUwKHJvd190aW1lJGJlZm9yZSwgcm93X3RpbWUkYWZ0ZXIpCiAgICB0aW1lIDwtIGFzLmludGVnZXIocm93X3RpbWUkdGltZSkKICAgIHN0YXRlcyA8LSBzcGxpdChkYXRhLCB0aW1lKQogICAgdGltZXMgPC0gYXMuaW50ZWdlcihuYW1lcyhzdGF0ZXMpKQogICAgbmZyYW1lcyA8LSBkaWZmKHRpbWVzKQogICAgbmZyYW1lc1sxXSA8LSBuZnJhbWVzWzFdICsgMQogICAgaWYgKHRpbWVzWzFdIDw9IDEpIHsKICAgICAgYWxsX2ZyYW1lcyA8LSBzdGF0ZXNbWzFdXQogICAgICBzdGF0ZXMgPC0gc3RhdGVzWy0xXQogICAgfQogICAgZWxzZSB7CiAgICAgIGFsbF9mcmFtZXMgPC0gZGF0YVswLCAsIGRyb3AgPSBGQUxTRV0KICAgICAgbmZyYW1lcyA8LSBjKHRpbWVzWzFdIC0gMSwgbmZyYW1lcykKICAgIH0KICAgIGlmICh0aW1lc1tsZW5ndGgodGltZXMpXSA8IHBhcmFtcyRuZnJhbWVzKSB7CiAgICAgIHN0YXRlcyA8LSBjKHN0YXRlcywgbGlzdChkYXRhWzAsICwgZHJvcCA9IEZBTFNFXSkpCiAgICAgIG5mcmFtZXMgPC0gYyhuZnJhbWVzLCBwYXJhbXMkbmZyYW1lcyAtIHRpbWVzW2xlbmd0aCh0aW1lcyldKQogICAgfQogICAgZm9yIChpIGluIHNlcV9hbG9uZyhzdGF0ZXMpKSB7CiAgICAgIGFsbF9mcmFtZXMgPC0gc3dpdGNoKHR5cGUsIHBvaW50ID0gdHdlZW5fc3RhdGUoYWxsX2ZyYW1lcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGVzW1tpXV0sIGVhc2UsIG5mcmFtZXNbaV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICEhaWQsIGVudGVyLCBleGl0KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdGggPSB0cmFuc2Zvcm1fcGF0aChhbGxfZnJhbWVzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRlc1tbaV1dLCBlYXNlLCBuZnJhbWVzW2ldLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICEhaWQsIGVudGVyLCBleGl0LCBtYXRjaCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICBwb2x5Z29uID0gdHJhbnNmb3JtX3BvbHlnb24oYWxsX2ZyYW1lcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0ZXNbW2ldXSwgZWFzZSwgbmZyYW1lc1tpXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAhIWlkLCBlbnRlciwgZXhpdCwgbWF0Y2gpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgc2YgPSB0cmFuc2Zvcm1fc2YoYWxsX2ZyYW1lcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRlc1tbaV1dLCBlYXNlLCBuZnJhbWVzW2ldLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgISFpZCwgZW50ZXIsIGV4aXQpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RvcCh0eXBlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiIGxheWVycyBub3QgY3VycmVudGx5IHN1cHBvcnRlZCBieSB0cmFuc2l0aW9uX3RpbWUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYWxsLiA9IEZBTFNFKSkKICAgIH0KICAgIHRydWVfZnJhbWUgPC0gc2VxKHRpbWVzWzFdLCB0aW1lc1tsZW5ndGgodGltZXMpXSkKICAgIGFsbF9mcmFtZXMgPC0gYWxsX2ZyYW1lc1sKICAgICAgYWxsX2ZyYW1lcyQuZnJhbWUgJWluJSAKICAgICAgICAjIHdoaWNoKHRydWVfZnJhbWUgPiAwICYgdHJ1ZV9mcmFtZSA8PSBwYXJhbXMkbmZyYW1lcyksCiAgICAgICAgdHJ1ZV9mcmFtZVt3aGljaCh0cnVlX2ZyYW1lID4gMCAmIHRydWVfZnJhbWUgPD0gcGFyYW1zJG5mcmFtZXMpXSwgIyB0d2VhayBsaW5lIEEKICAgICAgLCAKICAgICAgZHJvcCA9IEZBTFNFXQogICAgIyBhbGxfZnJhbWVzJC5mcmFtZSA8LSBhbGxfZnJhbWVzJC5mcmFtZSAtIG1pbihhbGxfZnJhbWVzJC5mcmFtZSkgKyAxICMgcmVtb3ZlIGxpbmUgQgogICAgYWxsX2ZyYW1lcyRncm91cCA8LSBwYXN0ZTAoYWxsX2ZyYW1lcyRncm91cCwgIjwiLCBhbGxfZnJhbWVzJC5mcmFtZSwgIj4iKQogICAgYWxsX2ZyYW1lcyQuZnJhbWUgPC0gTlVMTAogICAgYWxsX2ZyYW1lcwogIH0pCgp0cmFuc2l0aW9uX3RpbWUyIDwtIGZ1bmN0aW9uICh0aW1lLCByYW5nZSA9IE5VTEwpIHsKICB0aW1lX3F1byA8LSBlbnF1byh0aW1lKQogIGdnYW5pbWF0ZTo6OnJlcXVpcmVfcXVvKHRpbWVfcXVvLCAidGltZSIpCiAgZ2dwcm90byhOVUxMLCBUcmFuc2l0aW9uVGltZTIsIAogICAgICAgICAgcGFyYW1zID0gbGlzdCh0aW1lX3F1byA9IHRpbWVfcXVvLCByYW5nZSA9IHJhbmdlKSkKfQpgYGAKCmBgYHtyIGV4dHJhX2xvYWRzX29kZF9iZWZvcmUsIGVjaG89RkFMU0UsIHJlc3VsdHM9RkFMU0V9CmxpYnJhcnkoZ2dyYXBoKQpsaWJyYXJ5KGdnZm9yY2UpCmxpYnJhcnkoZ2dhbmltYXRlKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoaWdyYXBoKQpsaWJyYXJ5KGFuaW1hdGlvbikKbGlicmFyeShsdWJyaWRhdGUpCgoKcmVzdWx0czwtbWVyZ2UoeD14LHk9ZXh0cmVtX0FQLmRmbS5sb25nLCBieS54PSdkb2NfaWQnLCAgYnkueSA9IDAgICxhbGwueD1UUlVFKQpyZXN1bHRzX29kZC5iZWZvcmUgPC0gcmVzdWx0c1tyZXN1bHRzJGRvY19pZCAlJSAyID09IDEsXQpyZXN1bHRzX2V2ZW4uYWZ0ZXIgPC1yZXN1bHRzW3Jlc3VsdHMkZG9jX2lkICUlIDIgPT0gMCwgXQoKY29vY195ZWFyPC0gZGF0YS5mcmFtZSgpCgpmb3IoeSBpbiB1bmlxdWUocmVzdWx0c19vZGQuYmVmb3JlJHB1YnllYXIpKXsKICAjIHByaW50KHkpCiAgY29vYyA8LSBjb29jY3VycmVuY2UoeCA9IHN1YnNldChmaWx0ZXIocmVzdWx0c19vZGQuYmVmb3JlLCBwdWJ5ZWFyID09IHkpLCB1cG9zICVpbiUgYygiTk9VTiIsICJBREoiKSksIAogICAgICAgICAgICAgICAgICAgICAgIHRlcm0gPSAibGVtbWEiLCAKICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9IGMoImRvY19pZCIsICJwYXJhZ3JhcGhfaWQiLCAic2VudGVuY2VfaWQiKSkKICBjb29jJHllYXIgPC0geQogIGNvb2M8LSBoZWFkKGNvb2MsIDE0KQogIGNvb2NfeWVhciA8LSByYmluZChjb29jX3llYXIsIGNvb2MpCn0KCndvcmRuZXR3b3JrIDwtIGNvb2NfeWVhcgoKZ2dyYXBoKHdvcmRuZXR3b3JrLCBsYXlvdXQgPSAiZnIiKSArCiAgZ2VvbV9lZGdlX2xpbmsoYWVzKHdpZHRoID0gY29vYywgZWRnZV9hbHBoYSA9IGNvb2MpLCBlZGdlX2NvbG91ciA9ICJwaW5rIikgKwogIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IG5hbWUpLCBjb2wgPSAiZGFya2dyZWVuIiwgc2l6ZSA9IDQpICsKICB0aGVtZV9ncmFwaChiYXNlX2ZhbWlseSA9ICJBcmlhbCBOYXJyb3ciKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgIyBmYWNldF93cmFwX3BhZ2luYXRlKH55ZWFyKSsKICBzY2FsZV9hbHBoYV9pZGVudGl0eSgpKwogIGxhYnModGl0bGUgPSAiQ29vY2N1cnJlbmNlcyB3aXRoaW4gc2VudGVuY2U6IEJFRk9SRSIsIHN1YnRpdGxlID0gIk5vdW5zICYgQWRqZWN0aXZlIHtmcmFtZV90aW1lfSIpKwogIHRyYW5zaXRpb25fdGltZTIoeWVhcikKICBlYXNlX2FlcygnbGluZWFyJykKCiMgcGxvdChwKQojIHAKCiMgbGFzdF9hbmltYXRpb24oKQoKYGBgCmBgYHtyIGV4dHJhX2xvYWRzX2V2ZW5fYWZ0ZXIsIGVjaG89RkFMU0UsIHJlc3VsdHM9RkFMU0V9Cgpjb29jX3llYXI8LSBkYXRhLmZyYW1lKCkKCmZvcih5IGluIHVuaXF1ZShyZXN1bHRzX2V2ZW4uYWZ0ZXIkcHVieWVhcikpewogICMgcHJpbnQoeSkKICBjb29jIDwtIGNvb2NjdXJyZW5jZSh4ID0gc3Vic2V0KGZpbHRlcihyZXN1bHRzX2V2ZW4uYWZ0ZXIsIHB1YnllYXIgPT0geSksIHVwb3MgJWluJSBjKCJOT1VOIiwgIkFESiIpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgdGVybSA9ICJsZW1tYSIsIAogICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gYygiZG9jX2lkIiwgInBhcmFncmFwaF9pZCIsICJzZW50ZW5jZV9pZCIpKQogIGNvb2MkeWVhciA8LSB5CiAgY29vYzwtIGhlYWQoY29vYywgMTQpCiAgY29vY195ZWFyIDwtIHJiaW5kKGNvb2NfeWVhciwgY29vYykKfQoKCndvcmRuZXR3b3JrIDwtIGNvb2NfeWVhcgoKZ2dyYXBoKHdvcmRuZXR3b3JrLCBsYXlvdXQgPSAiZnIiKSArCiAgZ2VvbV9lZGdlX2xpbmsoYWVzKHdpZHRoID0gY29vYywgZWRnZV9hbHBoYSA9IGNvb2MpLCBlZGdlX2NvbG91ciA9ICJwaW5rIikgKwogIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IG5hbWUpLCBjb2wgPSAiZGFya2dyZWVuIiwgc2l6ZSA9IDQpICsKICB0aGVtZV9ncmFwaChiYXNlX2ZhbWlseSA9ICJBcmlhbCBOYXJyb3ciKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgIyBmYWNldF93cmFwX3BhZ2luYXRlKH55ZWFyKSsKICBzY2FsZV9hbHBoYV9pZGVudGl0eSgpKwogIGxhYnModGl0bGUgPSAiQ29vY2N1cnJlbmNlcyB3aXRoaW4gc2VudGVuY2U6IEFGVEVSIiwgc3VidGl0bGUgPSAiTm91bnMgJiBBZGplY3RpdmUge2ZyYW1lX3RpbWV9IikrCiAgdHJhbnNpdGlvbl90aW1lMih5ZWFyKQogIGVhc2VfYWVzKCdsaW5lYXInKQoKIyBwbG90KHAyKQojIHAyCgojIGxhc3RfYW5pbWF0aW9uKCkKCmBgYAoKYGBge3IgY29vYzJfYmVmb3JlLCBlY2hvPUZBTFNFLCByZXN1bHRzPUZBTFNFfQoKY29vYzJfeWVhcjwtIGRhdGEuZnJhbWUoKQoKZm9yKHkgaW4gdW5pcXVlKHJlc3VsdHNfb2RkLmJlZm9yZSRwdWJ5ZWFyKSl7CiAgIyBwcmludCh5KQogIGE8LSBmaWx0ZXIocmVzdWx0c19vZGQuYmVmb3JlLCBwdWJ5ZWFyID09IHkpCiAgCiAgY29vYyA8LSBjb29jY3VycmVuY2UoYSRsZW1tYSwgcmVsZXZhbnQgPSBhJHVwb3MgJWluJSBjKCJOT1VOIiwgIkFESiIpLCBza2lwZ3JhbSA9IDEpCiAgY29vYyR5ZWFyIDwtIHkKICBjb29jPC0gaGVhZChjb29jLCAxMikKICBjb29jMl95ZWFyIDwtIHJiaW5kKGNvb2MyX3llYXIsIGNvb2MpCn0KCgp3b3JkbmV0d29yayA8LSBjb29jMl95ZWFyCgpnZ3JhcGgod29yZG5ldHdvcmssIGxheW91dCA9ICJmciIpICsKICBnZW9tX2VkZ2VfbGluayhhZXMod2lkdGggPSBjb29jLCBlZGdlX2FscGhhID0gY29vYyksIGVkZ2VfY29sb3VyID0gInBpbmsiKSArCiAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFtZSksIGNvbCA9ICJkYXJrZ3JlZW4iLCBzaXplID0gNCkgKwogIHRoZW1lX2dyYXBoKGJhc2VfZmFtaWx5ID0gIkFyaWFsIE5hcnJvdyIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICAjIGZhY2V0X3dyYXBfcGFnaW5hdGUofnllYXIpKwogIHNjYWxlX2FscGhhX2lkZW50aXR5KCkrCiAgbGFicyh0aXRsZSA9ICJDb29jY3VycmVuY2VzIHdpdGhpbiBzZW50ZW5jZTogQkVGT1JFIiwgc3VidGl0bGUgPSAiTm91bnMgJiBBZGplY3RpdmUge2ZyYW1lX3RpbWV9IikrCiAgdHJhbnNpdGlvbl90aW1lMih5ZWFyKQogIGVhc2VfYWVzKCdsaW5lYXInKQoKIyBwbG90KHAzKQojIHAzCgojIGxhc3RfYW5pbWF0aW9uKCkKCmBgYApgYGB7ciBjb29jMl9hZnRlciwgZWNobz1GQUxTRSwgcmVzdWx0cz1GQUxTRX0KCmNvb2MyX3llYXI8LSBkYXRhLmZyYW1lKCkKCmZvcih5IGluIHVuaXF1ZShyZXN1bHRzX2V2ZW4uYWZ0ZXIkcHVieWVhcikpewogICMgcHJpbnQoeSkKICBhPC0gZmlsdGVyKHJlc3VsdHNfZXZlbi5hZnRlciwgcHVieWVhciA9PSB5KQogIAogIGNvb2MgPC0gY29vY2N1cnJlbmNlKGEkbGVtbWEsIHJlbGV2YW50ID0gYSR1cG9zICVpbiUgYygiTk9VTiIsICJBREoiKSwgc2tpcGdyYW0gPSAxKQogIGNvb2MkeWVhciA8LSB5CiAgY29vYzwtIGhlYWQoY29vYywgMTIpCiAgY29vYzJfeWVhciA8LSByYmluZChjb29jMl95ZWFyLCBjb29jKQp9CgoKd29yZG5ldHdvcmsgPC0gY29vYzJfeWVhcgoKZ2dyYXBoKHdvcmRuZXR3b3JrLCBsYXlvdXQgPSAiZnIiKSArCiAgZ2VvbV9lZGdlX2xpbmsoYWVzKHdpZHRoID0gY29vYywgZWRnZV9hbHBoYSA9IGNvb2MpLCBlZGdlX2NvbG91ciA9ICJwaW5rIikgKwogIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IG5hbWUpLCBjb2wgPSAiZGFya2dyZWVuIiwgc2l6ZSA9IDQpICsKICB0aGVtZV9ncmFwaChiYXNlX2ZhbWlseSA9ICJBcmlhbCBOYXJyb3ciKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgIyBmYWNldF93cmFwX3BhZ2luYXRlKH55ZWFyKSsKICBzY2FsZV9hbHBoYV9pZGVudGl0eSgpKwogIGxhYnModGl0bGUgPSAiQ29vY2N1cnJlbmNlcyB3aXRoaW4gc2VudGVuY2U6IEFGVEVSIiwgc3VidGl0bGUgPSAiTm91bnMgJiBBZGplY3RpdmUge2ZyYW1lX3RpbWV9IikrCiAgdHJhbnNpdGlvbl90aW1lMih5ZWFyKQogIGVhc2VfYWVzKCdsaW5lYXInKQoKIyBwbG90KHA0KQojIHA0CiMgbGFzdF9hbmltYXRpb24oKQoKYGBgCgoKCgpgYGB7ciBmaW5hbCwgZWNobz1GQUxTRX0KCnJtKGxpc3Q9bHMoKSkKCmBgYAoKCgoKCgoKCltob21lXShodHRwczovL2JyZWdyZWVuLmdpdGh1Yi5pby8pCg==